"""
功能描述：
此文件中处理了银企前置机的影像影像从前置机自动同步的综合业务系统中
1、监控指定目录中的文件，有生成的文件进行处理
2、上传文件到综合系统，同时生成回音影像的文件的接口数据
时间：2020年9月
版本：V1.0
作者：lisheng
"""
import shutil
import uuid

import pymysql
import win32file
import requests
import win32con
import configparser
import os
import logging.config
import json
import time

cf = configparser.ConfigParser()
cf.read('config\dbconfig.ini', encoding='utf-8')

ACTIONS = {
    1: "Created",
    2: "Deleted",
    3: "Updated",
    4: "Renamed from something",
    5: "Renamed to something"
}

FILE_LIST_DIRECTORY = win32con.GENERIC_READ | win32con.GENERIC_WRITE
# path_to_watch = "."
path_to_watch = "C:/Program Files/CMB/FbSdk/Receipt"
path_to_backup = "C:/Program Files/CMB/FbSdk/Backup"
hDir = win32file.CreateFile(
    path_to_watch,
    FILE_LIST_DIRECTORY,
    win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
    None,
    win32con.OPEN_EXISTING,
    win32con.FILE_FLAG_BACKUP_SEMANTICS,
    None
)


def init_logging(default_path="cmbbankfileconfig.json", default_level=logging.INFO, env_key="LOG_CFG"):
    """
    初始化日志记录的参数
    把日志记录的参数写入到配置文件中。
    配置文件的目录 为Config/logconfig.json
    产生的Log文件，放入至Logs目录中
    """
    path = default_path
    value = os.getenv(env_key, None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path, "r", encoding='utf-8') as f:
            config = json.load(f)
            logging.config.dictConfig(config)
    else:
        logging.basicConfig(level=default_level)


def uploadfiletobiz(filepath, filename, backuppath):
    """
    将文件上传到综合业务平台
    先检查文件是否已经下载处理过，如果没有处理过，先上传然后将文件移入备份文件夹。
    部署时，要在银行前置机的安装目录中，增加与接收文件同级的backup目录
    :param filename:  文件名称
    :param filepath:  文件全路径
    :param backuppath: 监控目录
    :return:
    """
    url = cf.get("bizfile", "URL")

    backupfile = backuppath + "/" + filename

    if os.path.exists(backupfile):
        # 如果文件已经在备份文件夹中存在，删除当前文件夹的文件
        os.remove(full_filename)
        logging.info("回单文件已经处理过，文件名为：%s" % filename)
        return None

    payload = {'userId': cf.get("bizfile", "USERID"),
               'password': cf.get("bizfile", "PASSWORD")}
    f1 = open(filepath, 'rb')
    files = [('file1', (filename, f1, 'text/plain'))]

    headers = {}
    # headers['content-type'] = "multipart/form-data;charset=utf-8"

    resp = requests.request("POST", url, headers=headers, data=payload, files=files)
    # 如果没有上传成功直接抛出异常
    if resp.status_code != 200:
        raise Exception("上传文件出错！post error status_code != 200" + str(resp.status_code))

    # 解析反馈数据，取得FileID
    respjson = json.loads(resp.text)
    bizfileid = respjson["data"][0]["FileID"]

    f1.close()
    # 文件上传成功后将原文件移至备份文件夹中
    shutil.move(full_filename, backupfile)
    logging.info("文件上传成功！文件全路径名为：%s" % filepath)
    return bizfileid


def uploadfiledatatobiz(fileID, filename):
    """
    更新银行回单的文件记录
    :param fileID: 上传的文件ID
    :param filename: 上传的文件名称
    :return:
    """
    govdb = pymysql.connect(cf.get('mysql', 'DB_HOST'), cf.get('mysql', 'DB_USER'),
                            cf.get('mysql', 'DB_PWD'), cf.get('mysql', 'DB_NAME'))
    cr = govdb.cursor()
    tmp = str.split(filename, "_")[3]
    refnbr = tmp[:tmp.find('.')]
    wj = '<file><_id>' + fileID + '</_id></file>'
    guid = refnbr
    # guid = str(uuid.uuid4()).replace("-", "") # ID暂用银行的流水处理，如果发现银行流水有重复，再考虑UUID的方式

    strinsertsql = "insert into t_lpromis_jkgl_yhjywjb (id,wj,refnbr) value ('" + \
                   guid + "','" + wj + "','" + refnbr + "') ON DUPLICATE KEY UPDATE WJ=VALUES(WJ)"
    try:
        cr.execute(strinsertsql)
        logging.info("回单影像数据生成成功！执行SQL语句为：%s" % (strinsertsql))
        govdb.commit()
    except Exception as err:
        logging.exception("插入回单影像数据错误,错误代码：%s，执行的SQL语句为%s" % (err, strinsertsql))
        govdb.rollback()

    # finally:
    #     govdb.close()

    govdb.close()
    return guid


if __name__ == '__main__':
    init_logging(default_path="config//cmbbankfileconfig.json")
    logging.info('系统开始运行')
    while 1:

        results = win32file.ReadDirectoryChangesW(
            hDir,
            # handle: Handle to the directory to be monitored. This directory must be opened with the FILE_LIST_DIRECTORY access right.
            1024,  # size: Size of the buffer to allocate for the results.
            True,
            # bWatchSubtree: Specifies whether the ReadDirectoryChangesW function will monitor the directory or the directory tree.
            win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
            win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
            win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
            win32con.FILE_NOTIFY_CHANGE_SIZE |
            win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
            win32con.FILE_NOTIFY_CHANGE_SECURITY,
            None,
            None)
        for action, file in results:
            if ACTIONS.get(action, "Unknown") == "Created":
                full_filename = os.path.join(path_to_watch, file)
                fileid = uploadfiletobiz(full_filename, file, path_to_backup)
                # 如果文件上传成功，则返回文件ID，否则为None，为None时不生成数据库数据。
                if fileid is not None:
                    bizid = uploadfiledatatobiz(fileid, file)
                print(full_filename, ACTIONS.get(action, "Unknown"))
